package graphics.seal;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import com.sun.corba.se.impl.ior.ByteBuffer;

import graphics.base.BaseUtil;
import graphics.base.Data3D;
import graphics.base.ExploreSTL;
import graphics.base.Point3D;
import graphics.base.TransformParam;
import graphics.base.Triangle;

public class ImageConvert3D {
	private static final int SIDE_WIDTH = 900;// 使模型清晰
	private static final int SEAL_BOTTOM_HEIGHT = SIDE_WIDTH * 25 / 300;
	private static final int BORDER_WIDTH = SIDE_WIDTH * 15 / 300;
	private static final int PAD_WIDTH_1 = SIDE_WIDTH * 20 / 300;
	private static final int PAD_WIDTH_2 = SIDE_WIDTH * 15 / 300;
	private static final int PAD_WIDTH_3 = SIDE_WIDTH * 10 / 300;
	private static final int PAD_WIDTH_4 = SIDE_WIDTH * 10 / 300;
	private static final int SEAL_FONT_SLIM = SIDE_WIDTH / 900 * 30;

	/*
	 * 二值化图片抓化成3D
	 */
	public static Data3D generateSealBottom(BufferedImage binaryImage) {
		List<Triangle> list = new ArrayList<Triangle>();
		Data3D seal = new Data3D(list);
		int intMinDepth = 0;// 图片原本的z最低
		int intMaxDepth = 0;// 图片原本的z最高
		int intImageWidth = binaryImage.getWidth();
		int intImageHeight = binaryImage.getHeight();

		int intHeights[][] = new int[intImageWidth + 2][intImageHeight + 2];
		// 规模
		float scaleRate = 30f / (intImageWidth + 2);
		// 用于减少重复计算的点
		byte bitTopDone[][] = new byte[intImageWidth + 2][intImageHeight + 2];
		for (int x = 0; x < intImageWidth; x++) {
			for (int y = 0; y < intImageHeight; y++) {
				bitTopDone[x][y] = 0;
			}
		}
		// 为了模型封闭,矩阵放宽,所以横列+2
		// calculate iniMinDepth
		// 目前印章字是红色,底是白色
		for (int x = 0; x < intImageWidth; x++) {
			for (int y = 0; y < intImageHeight; y++) {
				intHeights[x + 1][intImageHeight - y] = 255 - red(binaryImage.getRGB(x, y));
				if (intHeights[x + 1][intImageHeight - y] < intMinDepth) {
					intMinDepth = intHeights[x + 1][intImageHeight - y];
				}
				if (intHeights[x + 1][intImageHeight - y] > intMaxDepth) {
					intMaxDepth = intHeights[x + 1][intImageHeight - y];
				}
			}
		}

		// 印章底面为正方体,边长30mm,厚度2.5,计算出最大高度
		int calculateHMax = (intImageWidth + 2) * SEAL_BOTTOM_HEIGHT / SIDE_WIDTH;
		for (int x = 0; x < intImageWidth; x++) {
			for (int y = 0; y < intImageHeight; y++) {
				intHeights[intImageWidth - x][intImageHeight - y] = calculateHMax * (intHeights[intImageWidth - x][intImageHeight - y] - intMinDepth)
						/ (intMaxDepth - intMinDepth);
			}
		}
		// 需要添加两个triangle,做模型底面
		Triangle bottom1 = new Triangle();
		bottom1.setFirstPoint(binaryImage.getWidth() + 1, binaryImage.getHeight() + 1, 0);
		bottom1.setSecodePoint(binaryImage.getWidth() + 1, 0, 0);
		bottom1.setThridPoint(0, 0, 0);
		bottom1.toScale(scaleRate);

		Triangle bottom2 = new Triangle();
		bottom2.setFirstPoint(binaryImage.getWidth() + 1, binaryImage.getHeight() + 1, 0);
		bottom2.setSecodePoint(0, binaryImage.getHeight() + 1, 0);
		bottom1.setThridPoint(0, 0, 0);
		bottom2.toScale(scaleRate);
		list.add(bottom1);
		list.add(bottom2);

		int intBlockSize = 0;
		// 利用color计算高度
		for (int x = 0; x < intImageWidth + 1; x++) {
			for (int y = 0; y < intImageHeight + 1; y++) {
				// 这个点还没被计算
				if (bitTopDone[x][y] == 0) {
					// 为了减少计算量,排除没高度的区域
					if (intHeights[x][y] > 0 || intHeights[x + 1][y] > 0 || intHeights[x][y + 1] > 0 || intHeights[x + 1][y + 1] > 0) {
						intBlockSize = 0;

						boolean bitNoMatch = false;
						// (x,y)点之后的图片最长边
						int intMatchSize = 0;
						int intTemp1 = intImageWidth - x;
						int intTemp2 = intImageHeight - y;
						if (intTemp1 > intTemp2) {
							intMatchSize = intTemp1;
						} else {
							intMatchSize = intTemp2;
						}

						for (int i = 1; i < intMatchSize + 1; i++) {
							for (int j = 0; j < intMatchSize + 1; j++) {
								if (intHeights[x][y] != intHeights[x + i][y + j] || intHeights[x][y] != intHeights[x + j][y + i]) {
									bitNoMatch = true;// 与前面正方形区域高度不一致
									break;
								}
							}
							if (bitNoMatch)
								break;
							else
								intBlockSize = i - 1;// 记录高度一致的正方形大小
						}

						for (int i = 1; i < intBlockSize; i++) {
							for (int j = 0; j < intBlockSize; j++) {
								bitTopDone[x + i][y + j] = 1;// 记录被计算的正方形区域
							}
						}
						intBlockSize += 1;// 为了模型是密封的,边的高度与区域的高度不一样

						Triangle objTriangle1 = new Triangle();
						objTriangle1.setFirstPoint(x, y, intHeights[x][y]);
						objTriangle1.setSecodePoint(x + intBlockSize, y + intBlockSize, intHeights[x + intBlockSize][y + intBlockSize]);
						objTriangle1.setThridPoint(x, y + intBlockSize, intHeights[x][y + intBlockSize]);
						objTriangle1.toScale(scaleRate);

						Triangle objTriangle2 = new Triangle();
						objTriangle2.setFirstPoint(x, y, intHeights[x][y]);
						objTriangle2.setSecodePoint(x + intBlockSize, y, intHeights[x + intBlockSize][y]);
						objTriangle2.setThridPoint(x + intBlockSize, y + intBlockSize, intHeights[x + intBlockSize][y + intBlockSize]);
						objTriangle2.toScale(scaleRate);
						list.add(objTriangle1);
						list.add(objTriangle2);
					}
				}
			}
			intBlockSize = 0;
		}

		//
		// 补全(x == intImageWidth && y == 1)
		//
		Triangle objTriangle3 = new Triangle();
		objTriangle3.setFirstPoint(intImageWidth, 1, intHeights[intImageWidth][1]);
		objTriangle3.setSecodePoint(intImageWidth + 1, 0, intHeights[intImageWidth + 1][0]);
		objTriangle3.setThridPoint(intImageWidth, 0, intHeights[intImageWidth][0]);
		objTriangle3.toScale(scaleRate);

		Triangle objTriangle4 = new Triangle();
		objTriangle4.setFirstPoint(intImageWidth, 1, intHeights[intImageWidth][1]);
		objTriangle4.setSecodePoint(intImageWidth + 1, 0, intHeights[intImageWidth + 1][0]);
		objTriangle4.setThridPoint(intImageWidth + 1, 1, intHeights[intImageWidth + 1][1]);
		objTriangle4.toScale(scaleRate);
		list.add(objTriangle3);
		list.add(objTriangle4);

		//
		// 补全(x == 1 && y == intImageHeight)
		//
		Triangle objTriangle5 = new Triangle();
		objTriangle5.setFirstPoint(1, intImageHeight, intHeights[1][intImageHeight]);
		objTriangle5.setSecodePoint(0, intImageHeight + 1, intHeights[0][intImageHeight + 1]);
		objTriangle5.setThridPoint(0, intImageHeight, intHeights[0][intImageHeight]);
		objTriangle5.toScale(scaleRate);

		Triangle objTriangle6 = new Triangle();
		objTriangle6.setFirstPoint(1, intImageHeight, intHeights[1][intImageHeight]);
		objTriangle6.setSecodePoint(0, intImageHeight + 1, intHeights[0][intImageHeight + 1]);
		objTriangle6.setThridPoint(1, intImageHeight + 1, intHeights[1][intImageHeight + 1]);
		objTriangle6.toScale(scaleRate);
		list.add(objTriangle5);
		list.add(objTriangle6);

		// 反转
		float rmax = calculateHMax * scaleRate;
		for (int i = 0; i < list.size(); i++) {
			Triangle tri = list.get(i);
			tri.z1 = rmax - tri.z1;
			tri.z2 = rmax - tri.z2;
			tri.z3 = rmax - tri.z3;
		}
		seal.calculateMaxAndMin();
		return seal;
	}

	/**
	 * 添加边框
	 * 
	 * @param bitmap
	 * @param color
	 */
	private static void addBorder(BufferedImage grayImg, int color) {
		int max = SIDE_WIDTH - BORDER_WIDTH;
		for (int x = 0; x < grayImg.getWidth(); x++) {
			for (int y = 0; y < grayImg.getWidth(); y++) {
				if (!(x >= BORDER_WIDTH && y >= BORDER_WIDTH && x < max && y < max))
					grayImg.setRGB(x, y, color);
			}
		}
	}

	/**
	 * 300*300dmm 生成bitmap
	 * 
	 * @param s
	 */
	public static BufferedImage generateBinaryImage(String s, int color, String fontKey) {
		BufferedImage binaryImg = new BufferedImage(SIDE_WIDTH, SIDE_WIDTH, BufferedImage.TYPE_BYTE_BINARY);
		if (s == null || s.isEmpty()) {
			return binaryImg;
		}
		for (int x = 0; x < binaryImg.getWidth(); x++) {
			for (int y = 0; y < binaryImg.getHeight(); y++) {
				binaryImg.setRGB(x, y, Color.WHITE.getRGB());
			}
		}
		addBorder(binaryImg, color);
		Graphics graphics = binaryImg.getGraphics();
		graphics.setColor(new Color(color));
		int center = SIDE_WIDTH / 2;
		switch (s.length()) {
		case 1:
			// | 1 |
			int min1 = BORDER_WIDTH + PAD_WIDTH_1;
			int max1 = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_1;
			int fontSize1 = max1 - min1;
			int baseline1 = fontSize1 / 6;
			Font font1 = ExtendFontCache.inc().get(fontKey).deriveFont((float) fontSize1);
			graphics.setFont(font1);
			graphics.drawString(s, min1, max1 - baseline1);
			// 基线比汉字下缘高
			tensile(binaryImg, min1, min1, max1, max1);
			erase(binaryImg, max1, min1, SIDE_WIDTH - BORDER_WIDTH - 1, max1);
			break;
		case 2:
			// | 1 2 |
			// 第一个字起点
			int b21x = BORDER_WIDTH + PAD_WIDTH_2;
			int b21y = b21x;
			int e21x = center - PAD_WIDTH_2 / 2;
			int e21y = e21x;
			// 第二个字起点
			int b22x = center + PAD_WIDTH_2 / 2;
			int b22y = b21y;
			int e22x = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_2;
			int e22y = e21y;

			int fontSize2 = e21x - b21x;
			int baseline2 = (e21x - b21x) / 6;

			// 字体右序
			String s21 = s.substring(1, 2);
			String s22 = s.substring(0, 1);

			Font font2 = ExtendFontCache.inc().get(fontKey).deriveFont((float) fontSize2);
			graphics.setFont(font2);
			graphics.drawString(s21, b21x, e21y - baseline2);
			graphics.drawString(s22, b22x, e22y - baseline2);

			int newEndY2 = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_2;

			tensile(binaryImg, b21x, b21y, e21x, newEndY2);
			tensile(binaryImg, b22x, b22y, e22x, newEndY2);

			erase(binaryImg, e21x, b21y, b22x, newEndY2);
			erase(binaryImg, e22x, b21y, SIDE_WIDTH - BORDER_WIDTH - 1, newEndY2);
			break;

		case 3:
			// |*1乙***|
			// |***2甲*|
			// |*3丙***|
			// 字体右序--甲乙丙
			String s31 = s.substring(1, 2);// 乙
			String s32 = s.substring(0, 1);// 甲
			String s33 = s.substring(2, 3);// 丙

			// 第一个字
			int b31x = BORDER_WIDTH + PAD_WIDTH_3;
			int b31y = b31x;
			int e31x = center - PAD_WIDTH_3 / 2;
			int e31y = e31x;

			int fontSize3 = e31x - b31x;
			int baseline3 = fontSize3 / 6;

			Font font3 = ExtendFontCache.inc().get(fontKey).deriveFont((float) fontSize3);
			graphics.setFont(font3);
			// 第二个字
			int b32x = center + PAD_WIDTH_3 / 2;
			int b32y = b31y;
			int e32x = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_3;
			int e32y = e31y;
			graphics.drawString(s32, b32x, e32y - baseline3);// 2

			// 第三个字
			int b33x = b31x;
			int b33y = center + PAD_WIDTH_3 / 2;
			int e33x = e31x;
			int e33y = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_3;
			graphics.drawString(s31, b31x, e31y - baseline3);// 1
			graphics.drawString(s33, b33x, e33y - baseline3);// 3

			tensile(binaryImg, b31x, b31y, e31x, e31y);
			tensile(binaryImg, b33x, b33y, e33x, e33y);
			tensile(binaryImg, b32x, b32y, e32x, e33y);

			erase(binaryImg, e31x, b31y, b32x, e33y);
			erase(binaryImg, e32x, b31y, SIDE_WIDTH - BORDER_WIDTH - 1, e33y);
			break;

		default:
			// |*1丙2甲*|
			// |*3丁4乙*|
			// 字体右序--甲乙丙丁
			String s41 = s.substring(2, 3);// 丙
			String s42 = s.substring(0, 1);// 甲
			String s43 = s.substring(3, 4);// 丁
			String s44 = s.substring(1, 2);// 乙

			// 第一个字
			int b41x = BORDER_WIDTH + PAD_WIDTH_4;
			int b41y = b41x;
			int e41x = center - PAD_WIDTH_4 / 2;
			int e41y = e41x;

			int b42x = center + PAD_WIDTH_4 / 2;
			int b42y = b41y;
			int e42x = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_4;
			int e42y = e41y;

			int b43x = b41x;
			int b43y = center + PAD_WIDTH_4 / 2;
			int e43x = e41x;
			int e43y = SIDE_WIDTH - BORDER_WIDTH - PAD_WIDTH_4;

			int b44x = b42x;
			int b44y = b43y;
			int e44x = e42x;
			int e44y = e43y;

			int fontSize4 = e41x - b41x;
			int baseline4 = (fontSize4) / 6;

			Font font4 = ExtendFontCache.inc().get(fontKey).deriveFont((float) fontSize4);
			graphics.setFont(font4);

			graphics.drawString(s41, b41x, e41y - baseline4);
			graphics.drawString(s42, b42x, e42y - baseline4);
			graphics.drawString(s43, b43x, e43y - baseline4);
			graphics.drawString(s44, b44x, e44y - baseline4);

			tensile(binaryImg, b41x, b41y, e41x, e41y);
			tensile(binaryImg, b42x, b42y, e42x, e42y);
			tensile(binaryImg, b43x, b43y, e43x, e43y);
			tensile(binaryImg, b44x, b44y, e44x, e44y);

			erase(binaryImg, e41x, b41y, b42x, e43y);
			erase(binaryImg, e42x, b41y, SIDE_WIDTH - BORDER_WIDTH - 1, e43y);
			break;
		}

		slimX(binaryImg, BORDER_WIDTH, BORDER_WIDTH, SIDE_WIDTH - BORDER_WIDTH, SIDE_WIDTH - BORDER_WIDTH, SEAL_FONT_SLIM);
		// eraseY(binaryImg, BORDER_WIDTH, BORDER_WIDTH, SIDE_WIDTH -
		// BORDER_WIDTH, SIDE_WIDTH - BORDER_WIDTH, 0.9f);

		graphics.dispose();
		return binaryImg;

	}

	/**
	 * 生成二值化图像
	 * 
	 * @param imgPath
	 * @return
	 */
	public static BufferedImage toBinaryImage(String imgPath) {

		BufferedImage BinaryImage = null;
		try {
			BufferedImage image = ImageIO.read(new File(imgPath));
			BinaryImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_BINARY);// 重点，技巧在这个参数BufferedImage.TYPE_BYTE_BINARY
			for (int i = 0; i < image.getWidth(); i++) {
				for (int j = 0; j < image.getHeight(); j++) {
					int rgb = image.getRGB(i, j);
					BinaryImage.setRGB(i, j, rgb);
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		return BinaryImage;
	}

	//
	// * 'Binary STL File format:
	// * '***************************************
	// * 'UINT8[80] – Header
	// * 'UINT32 – Number of triangles
	// * '
	// * 'foreach triangle
	// * 'REAL32[3] – Normal vector
	// * 'REAL32[3] – Vertex 1
	// * 'REAL32[3] – Vertex 2
	// * 'REAL32[3] – Vertex 3
	// * 'UINT16 – Attribute byte count
	// *'End
	public static void generateSTL(String stlPath, Data3D seal3D) {
		List<Triangle> list = seal3D.tris;
		ByteBuffer bbf = new ByteBuffer(80);
		bbf.append(BaseUtil.STL_FILE_HEAD);

		File stl = new File(stlPath);

		try {
			if (!stl.exists()) {
				stl.createNewFile();
			}
			FileOutputStream fos = new FileOutputStream(stl);
			DataOutputStream doutput = new DataOutputStream(fos);
			byte[] temp = new byte[4];

			doutput.write(bbf.toArray());// Header
			//
			int triNum = list.size();
			BaseUtil.toBytesLowFirst(triNum, temp);
			doutput.write(temp);// Number of triangles

			byte[] attribute = new byte[2];

			for (int i = 0; i < list.size(); i++) {

				Triangle tri = list.get(i);
				tri.calculateNormal();
				// normal
				BaseUtil.toBytesLowFirst(tri.nx, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.ny, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.nz, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x1, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y1, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z1, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x2, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y2, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z2, temp);
				doutput.write(temp);

				BaseUtil.toBytesLowFirst(tri.x3, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.y3, temp);
				doutput.write(temp);
				BaseUtil.toBytesLowFirst(tri.z3, temp);
				doutput.write(temp);

				doutput.write(attribute);
			}
			doutput.close();
			fos.close();

		} catch (IOException e) {
			e.printStackTrace();
		}

		return;
	}

	public static boolean generateSeal(Data3D sealBottom, String oriSealpath, String nSealPath) {

		List<Triangle> list = sealBottom.tris;
		Seal oriSeal = SealUtils.initSeal(oriSealpath);
		Point3D sealMinPoint = new Point3D(oriSeal.min.x, oriSeal.min.y, oriSeal.min.z);
		Point3D sealMaxPoint = new Point3D(oriSeal.max.x, oriSeal.max.y, oriSeal.max.z);

		Triangle i3DF = sealBottom.tris.get(0);// img3DFirst
		Point3D imgXYMinPoint = new Point3D(0, 0, i3DF.z1);// note
		float i3DFMaxX = Math.max(i3DF.x1, i3DF.x2) > i3DF.x3 ? Math.max(i3DF.x1, i3DF.x2) : i3DF.x3;
		float i3DFMaxY = Math.max(i3DF.y1, i3DF.y2) > i3DF.y3 ? Math.max(i3DF.y1, i3DF.y2) : i3DF.y3;
		Point3D imgXYMaxPoint = new Point3D(i3DFMaxX, i3DFMaxY, i3DF.z1);// note
		TransformParam tfp = SealUtils.initTransformParam(sealMinPoint, sealMaxPoint, imgXYMinPoint, imgXYMaxPoint);

		File seal = new File(nSealPath);
		try {
			if (!seal.exists()) {
				seal.createNewFile();
			}
			FileOutputStream fos = new FileOutputStream(seal);

			FileInputStream fis = new FileInputStream(oriSealpath);
			fis.skip(80);// 去掉文件头
			// add head
			byte[] facetNumBytes = new byte[4];
			fis.read(facetNumBytes);// 4
			int oldFacetNum = ExploreSTL.STLFaceNum(facetNumBytes);
			ByteBuffer bbf = new ByteBuffer(80);
			bbf.append(BaseUtil.STL_FILE_HEAD);
			fos.write(bbf.toArray());
			BaseUtil.toBytesLowFirst(oldFacetNum + list.size(), facetNumBytes);
			fos.write(facetNumBytes);

			// copy old
			byte[] copybf = new byte[1024];
			int len = 0;
			while ((len = fis.read(copybf)) != -1) {
				fos.write(copybf, 0, len);
			}
			fis.close();
			// add new
			byte[] tribf = new byte[50];
			for (int i = 0; i < list.size(); i++) {
				Triangle tri = list.get(i);
				tri.calculateNormal();
				tfp.transformTriangle(tri);// 变形
				BaseUtil.triangleToLowBytes(tri, tribf);
				fos.write(tribf);
			}
			fos.close();
			return true;

		} catch (IOException e) {
			e.printStackTrace();
		}
		return true;

	}

	/**
	 * 
	 * @param rgb
	 * @return
	 */
	private static int red(int rgb) {
		return (rgb >> 16) & 0xFF;
	}

	/**
	 * 水平拉伸
	 * 
	 * @param grayImg
	 * @param beginX
	 * @param beginY
	 * @param endX
	 * @param endY
	 */
	private static void tensileX(BufferedImage grayImg, int beginX, int beginY, int endX, int endY) {
		int space = Color.white.getRGB();
		int leftx = beginX;
		for (int x = beginX; x <= endX; x++) {
			for (int y = beginY; y <= endY; y++) {
				if (grayImg.getRGB(x, y) != space) {
					leftx = x;
					break;
				}
			}
			if (leftx != beginX)
				break;
		}
		if (leftx != beginX) {
			float plx = (endX - leftx) * 1.0f / (endX - beginX);
			for (int x = beginX; x <= endX; x++) {
				for (int y = beginY; y <= endY; y++) {
					grayImg.setRGB(x, y, grayImg.getRGB(Float.valueOf((x - beginX) * plx).intValue() + leftx, y));
				}
			}
		}
		// right
		int rightx = endX;
		for (int x = endX; x >= beginX; x--) {
			for (int y = endY; y >= beginY; y--) {
				if (grayImg.getRGB(x, y) != space) {
					rightx = x;
					break;
				}
			}
			if (rightx != endX)
				break;
		}
		if (rightx != endX) {
			float prx = (rightx - beginX) * 1.0f / (endX - beginX);
			for (int x = endX; x >= beginX; x--) {
				for (int y = endY; y >= beginY; y--) {
					grayImg.setRGB(x, y, grayImg.getRGB(Float.valueOf((x - beginX) * prx).intValue() + beginX, y));
				}
			}
		}
	}

	/**
	 * 垂直拉伸
	 * 
	 * @param grayImg
	 * @param beginX
	 * @param beginY
	 * @param endX
	 * @param endY
	 */
	private static void tensileY(BufferedImage grayImg, int beginX, int beginY, int endX, int endY) {
		int space = Color.white.getRGB();
		int topy = beginY;
		for (int y = beginY; y <= endY; y++) {
			for (int x = beginX; x <= endX; x++) {
				if (grayImg.getRGB(x, y) != space) {
					topy = y;
					break;
				}
			}
			if (topy != beginY)
				break;
		}
		if (topy != beginY) {
			float pty = (endY - topy) * 1.0f / (endY - beginY);
			for (int y = beginY; y <= endY; y++) {
				for (int x = beginX; x <= endX; x++) {
					grayImg.setRGB(x, y, grayImg.getRGB(x, Float.valueOf((y - beginY) * pty).intValue() + topy));
				}
			}
		}
		// bottom
		int bootomy = endY;
		for (int y = endY; y >= beginY; y--) {
			for (int x = endX; x >= beginX; x--) {
				if (grayImg.getRGB(x, y) != space) {
					bootomy = y;
					break;
				}
			}
			if (bootomy != endY)
				break;
		}
		if (bootomy != endY) {
			float pby = (bootomy - beginY) * 1.0f / (endY - beginY);
			for (int y = endY; y >= beginY; y--) {
				for (int x = endX; x >= beginX; x--) {
					grayImg.setRGB(x, y, grayImg.getRGB(x, Float.valueOf((y - beginY) * pby).intValue() + beginY));
				}
			}
		}
	}

	/**
	 * 拉伸指定区域
	 * 
	 * @param grayImg
	 * @param beginX
	 * @param beginY
	 * @param endX
	 * @param endY
	 */
	private static void tensile(BufferedImage grayImg, int beginX, int beginY, int endX, int endY) {
		tensileY(grayImg, beginX, beginY, endX, endY);
		tensileX(grayImg, beginX, beginY, endX, endY);
	}

	/**
	 * 字体横向变纤细
	 * 
	 * @param grayImg
	 * @param beginX
	 * @param beginY
	 * @param endX
	 * @param endY
	 * @param dist
	 *            纤细像素
	 */
	private static void slimX(BufferedImage grayImg, int beginX, int beginY, int endX, int endY, int dist) {
		int dist_helf = dist / 2;
		int LAST_BEGIN = -3;
		int space = Color.white.getRGB();
		int black = Color.BLACK.getRGB();
		int last = LAST_BEGIN;
		List<Integer> lineHead = new ArrayList<>();
		List<Integer> lineTail = new ArrayList<>();
		for (int y = beginY + 1; y < endY; y++) {
			for (int x = beginX + 1; x < endX; x++) {
				int now = grayImg.getRGB(x, y);
				if (last != LAST_BEGIN && now != last) {
					// color change,line head or tail
					if (last == space && now == black) {
						// head
						lineHead.add(x);
					} else if (last == black && now == space) {
						// tail
						lineTail.add(x);
					}
				}
				last = now;
			}
			int size = lineHead.size() < lineTail.size() ? lineHead.size() : lineTail.size();
			for (int i = 0; i < size; i++) {
				int headx = lineHead.get(i);
				int tailx = lineTail.get(i);

				int newHeadx = headx - dist_helf;
				int newTailx = tailx - dist_helf;
				for (int x1 = headx; x1 <= newHeadx; x1++) {
					grayImg.setRGB(x1, y, space);
				}
				for (int x1 = newTailx; x1 <= tailx; x1++) {
					grayImg.setRGB(x1, y, space);
				}
			}
			lineHead.clear();
			lineTail.clear();
		}
	}

	/**
	 * 使用白色擦除图像指定区域
	 * 
	 * @param grayImg
	 * @param beginX
	 * @param beginY
	 * @param endX
	 * @param endY
	 */
	private static void erase(BufferedImage grayImg, int beginX, int beginY, int endX, int endY) {
		int space = Color.white.getRGB();
		for (int y = beginY; y <= endY; y++) {
			for (int x = beginX; x <= endX; x++) {
				grayImg.setRGB(x, y, space);
			}
		}
	}

	public static void main(String[] args) {
		// String imgPath = "F:/test-stl/chinese-flag.jpg";
		// BufferedImage binaryImage = ImageConvert3D.toBinaryImage(imgPath);
		// ImageConvert3D.generateSeal(ImageConvert3D.generateSealBottom(binaryImage),
		// "F:/test-stl/08.stl",
		// "F:/test-stl/hui4.stl");

		BufferedImage binaryImage = ImageConvert3D.generateBinaryImage("女神牛静", Color.BLACK.getRGB(), ExtendFontCache.SEAL_CHARACTER_KEY);
		try {
			ImageIO.write(binaryImage, "jpg", new File("F:/test-stl/hui1.jpg"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
